package easyValidate

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

func init() {
	defaultOprateFuncMap = make(map[string]func(reflect.Value, ...string) bool, 3)
	defaultOprateFuncMap[PARAM_IT] = IT
	defaultOprateFuncMap[PARAM_GT] = GT
	defaultOprateFuncMap[PARAM_MAX] = MAX
	defaultOprateFuncMap[PARAM_LEN] = LEN
	defaultOprateFuncMap[PARAM_SELECT] = SELECT
	defaultOprateFuncMap[PARAM_GTE] = GTE
	defaultOprateFuncMap[PARAM_ITE] = ITE
}
type CheckParam [][]string

func splitCheckTag(str string) (CheckParam, error) {
	var err error
	if len(str) == 0 {
		err = errors.New("结构体无check标签或标签格式错误")
		return nil, err
	}
	var param CheckParam = make(CheckParam, 0, 3)
	fields := strings.Split(str, ",")
	for _, v := range fields {
		field := strings.Split(v, "=")
		if len(field) != 2 {
			err = fmt.Errorf("chenck标签编写错误:%v", v)
			return nil,  err
		}
		param = append(param, field)
	}
	return param, nil
}

func check(param CheckParam, val reflect.Value) bool {
	for _, tag := range param {
		if ok := defaultOprateFuncMap[tag[0]](val, tag[1:]...); !ok{
			return false
		}
	}
	return true
}

var defaultOprateFuncMap map[string]func(reflect.Value, ...string) bool

func GT(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	switch val.Kind().String() {
	case "float32","float64":
		origin := val.Float()
		if origin <= float64(compare) {
			return false
		}
		return true
	case "uint","uint8","uint16","uint32","uint64":
		origin := val.Uint()
		if origin <= uint64(compare) {
			return false
		}
		return true
	case "int","int8","int16","int32","int64":
		origin := val.Int()
		if origin <= int64(compare) {
			return false
		}
		return true
	default:
		return false
	}
}

func IT(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	switch val.Kind().String() {
	case "float32","float64":
		origin := val.Float()
		if origin >= float64(compare) {
			return false
		}
		return true
	case "uint","uint8","uint16","uint32","uint64":
		origin := val.Uint()
		if origin >= uint64(compare) {
			return false
		}
		return true
	case "int","int8","int16","int32","int64":
		origin := val.Int()
		if origin >= int64(compare) {
			return false
		}
		return true
	default:
		return false
	}
}

func ITE(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	switch val.Kind().String() {
	case "float32","float64":
		origin := val.Float()
		if origin > float64(compare) {
			return false
		}
		return true
	case "uint","uint8","uint16","uint32","uint64":
		origin := val.Uint()
		if origin > uint64(compare) {
			return false
		}
		return true
	case "int","int8","int16","int32","int64":
		origin := val.Int()
		if origin > int64(compare) {
			return false
		}
		return true
	default:
		return false
	}
}

func MAX(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	origin := val.Len()
	if origin > compare {
		return false
	}
	return true
}

func LEN(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	origin := val.Len()
	if origin != compare {
		return false
	}
	return true
}

func SELECT(val reflect.Value, std ...string) bool {
	options := strings.Split(strings.Trim(std[0], " "), " ")
	var str string
	switch val.Kind().String() {
	case "int","int8","int16","int32","int64":
		str = strconv.FormatInt(val.Int(), 10)
	case "uint","uint8","uint16","uint32","uint64":
		str = strconv.FormatUint(val.Uint(), 10)
	case "float32","float64":
		str = strconv.FormatFloat(val.Float(), 'f', -1, 64)
	case "string":
		str = val.String()
	default:
		return false
	}

	for _, v := range options {
		if str == v {
			return true
		}
	}
	return false
}

func GTE(val reflect.Value, std ...string) bool {
	compare, err := strconv.Atoi(std[0])
	if err != nil {
		return false
	}
	switch val.Kind().String() {
	case "float32","float64":
		origin := val.Float()
		if origin < float64(compare) {
			return false
		}
		return true
	case "uint","uint8","uint16","uint32","uint64":
		origin := val.Uint()
		if origin < uint64(compare) {
			return false
		}
		return true
	case "int","int8","int16","int32","int64":
		origin := val.Int()
		if origin < int64(compare) {
			return false
		}
		return true
	default:
		return false
	}
}


